from io import BytesIO, StringIO
import xlwt
from django.http import HttpResponse
from rest_framework import status
from host import models
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, ViewSet
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated  # 校验用户是否登录
from host.serializers import HostModelSerializers, HostCategoryModelSeiralizer
from hippo_api.utils.read_host_excel import read_host_excel_data
from hippo_api.utils.handle_key import AppSetting

class CategorysView(ListAPIView):
    queryset = models.HostCategory.objects.all()
    serializer_class = HostCategoryModelSeiralizer


class HostView(ModelViewSet):
    permission_classes = [IsAuthenticated, ]

    # 相同效果，获取queryset
    # 原来的方式1
    # queryset = models.Host.objects.all()
    # 方式2
    # def get_queryset(self):
    #     return models.Host.objects.all()

    # 相当与拦截queryset，返回自定义的queryset
    # 基于携带的查询参数，完成不同环境的主机数据筛选
    def get_queryset(self):
        env_id = self.request.query_params.get('env_id')
        # 如果查询时，有环境id，那么进行环境的筛选
        queryset = models.Host.objects.all()
        if env_id:
            queryset = queryset.filter(evrironments_id=env_id)
        return queryset
    serializer_class = HostModelSerializers


# 批量导入excel数据
# 直接跟数据打交道用modelViewSet,像这个和excel有逻辑,用APIView
class HostExcelView(APIView):
    permission_classes = [IsAuthenticated, ]

    # 上传host数据excel文件
    def post(self,request):
        # request.data中能够拿到通过formdata上传的文件和其他键值对数据
        print('request.data>>>>', request.data)
        default_password = request.data.get('default_password').strip()
        print(default_password)
        host_excel = request.data.get('host_excel')

        # 方式1 将文件保存在本机上 -> 读取excel文件数据
        # 创建一个excel的临时存储目录(根目录下创建tem_file)，先保存excel文件到本地，然后读取数据，保存，最后删除excel文件。

        # 方式2 将文件保存在bytes对象，内存字节空间，再读取（效率高）
        # 將文件數據保存到byteio對象,內存字節流空間
        sio = BytesIO()
        for i in host_excel:
            sio.write(i)

        # 读取字节流中excel数据,用xlrd,
        # 这里自己用xlrd封装了工具read_host_excel_data
        res_data = read_host_excel_data(sio, default_password)

        return Response(res_data)

    def get(self, request):
        # 1 读取数据库数据
        all_host_data = models.Host.objects.all().values('id', 'category', 'hostname', 'ip_addr', 'port', 'username',
                                                         'desc')
        print(all_host_data)

        # 2 写入excel并保存
        # 创建excel
        ws = xlwt.Workbook(encoding='utf-8')
        # 创建工作簿
        st = ws.add_sheet('主机数据')

        # 写标题行
        st.write(0, 0, 'id')
        st.write(0, 1, 'category')
        st.write(0, 2, 'hostname')
        st.write(0, 3, 'ip_addr')
        st.write(0, 4, 'port')
        st.write(0, 5, 'username')
        st.write(0, 6, 'desc')

        # 写入数据，从第一行开始
        excel_row = 1
        for host_obj in all_host_data:
            st.write(excel_row, 0, host_obj.get('id'))
            st.write(excel_row, 1, host_obj.get('category'))
            st.write(excel_row, 2, host_obj.get('hostname'))
            st.write(excel_row, 3, host_obj.get('ip_addr'))
            st.write(excel_row, 4, host_obj.get('port'))
            st.write(excel_row, 5, host_obj.get('username'))
            st.write(excel_row, 6, host_obj.get('desc'))
            excel_row += 1  # 从下一行开始

        # 将数据写入io数据流，不用在本地生成excel文件，不然效率就低了
        sio = BytesIO()
        ws.save(sio)
        sio.seek(0)

        # 3 将excel数据响应回客户端
        response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel')
        # response['Content-Disposition'] = 'attachment; filename=xx.xls'

        # 文件名称中文设置
        from django.utils.encoding import escape_uri_path
        response['Content-Disposition'] = 'attachment; filename={}'.format(escape_uri_path('主机列表数据.xls'))
        response.write(sio.getvalue())  # 必须要给response写入一下数据，不然不生效

        return response


# ViewSet 让方法名称更具有意义, 例如get_folders 获取文件目录信息
class HostFileView(ViewSet):
    # 方法分发之前，先获取要操作的主机id和链接
    def dispatch(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        host_obj = models.Host.objects.get(pk=pk)  # 先查出主机
        pkey = AppSetting.get('private_key')
        cli = host_obj.get_ssh(pkey)  # 获取私钥
        self.cli = cli  # 创建SSH链接
        ret = super().dispatch(request, *args, **kwargs)  # 处理完上面的任务,再执行父类方法 路由分发
        return ret

    # get_folders 获取某个目录的文件和文件夹信息列表
    def get_folders(self, request, pk):
        cmd = request.query_params.get('cmd')
        res_code, res_data = self.cli.exec_command(cmd)
        # print('!!!!!!!', res_code,res_data)
        return Response([res_code, res_data])

    def download_file(self, request, pk, file_path):
        pass

    def upload_file(self, request, pk):
        # 获取前端传来的路径参数
        folder_path = request.query_params.get('folder_path')

        # 获取文件对象
        file_obj = request.FILES.get('file')
        folder_path += f'/{file_obj.name}'  # 把前端传来的路径参数 和 文件对象名称，拼接一下
        # print(folder_path)
        file_size = file_obj.size

        try:
            self.cli.put_file_by_fl(file_obj, folder_path, self.file_upload_callback)
        except:
            return Response({'error': '文件上传失败,请联系管理员或者查看一下用户权限'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response({'msg': 'ok'})

    def delete_file(self, request, file_path):
        pass

    def file_upload_callback(self, n, k):
        print('>>>>>>>>>>>', n, k)